package com.lsh.payment.core.service.cmpay.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.payment.api.model.basevo.BaseResponse;
import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.api.model.payment.PaymentRequest;
import com.lsh.payment.api.model.qfpay.QfPayContent;
import com.lsh.payment.api.model.qfpay.QfResponse;
import com.lsh.payment.core.constant.BusinessConstant;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.model.payasync.payTaskModel;
import com.lsh.payment.core.model.payenum.PayStatus;
import com.lsh.payment.core.model.payenum.PayWay;
import com.lsh.payment.core.model.payment.PayDeal;
import com.lsh.payment.core.service.async.PayEventBus;
import com.lsh.payment.core.service.paylog.PayLogService;
import com.lsh.payment.core.service.payment.IPayChannelService;
import com.lsh.payment.core.service.payment.impl.PayBaseService;
import com.lsh.payment.core.service.payment.impl.PayDealService;
import com.lsh.payment.core.strategy.config.CmPayConfig;
import com.lsh.payment.core.strategy.payment.PayStrategyContext;
import com.lsh.payment.core.strategy.vo.cmpay.CmPayResponse;
import com.lsh.payment.core.util.PayAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * Project Name: lsh-payment
 *
 * @author peter
 * Date: 17/8/23
 * 北京链商电子商务有限公司
 * Package com.lsh.payment.core.service.xypay.impl
 * desc:
 */
@Service
@Transactional(readOnly = true)
public class CmPayServiceImpl implements IPayChannelService {

    private static Logger logger = LoggerFactory.getLogger(CmPayServiceImpl.class);

    @Autowired
    private PayBaseService payBaseService;

    @Autowired
    private PayDealService payDealService;

    @Autowired
    private PayLogService payLogService;

    @Resource
    private PayStrategyContext strategies;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse prepay(PaymentRequest paymentRequest) {
        //字段校验
        PayAssert.notNull(paymentRequest.getTrade_module(), ExceptionStatus.E1002002.getCode(), ExceptionStatus.E1002002.getMessage());
        if (!paymentRequest.getPay_way().equals(PayWay.ANDROID.getName()) && !paymentRequest.getPay_way().equals(PayWay.IOS.getName())) {
            throw new BusinessException(ExceptionStatus.E1002002.getCode(), "payWay 字段错误");
        }

        QfResponse<QfPayContent> response = new QfResponse<>();
        QfPayContent content = this.DealCmPayRequest(paymentRequest);
        response.setContent(content);
        response.setRet(Integer.parseInt(ExceptionStatus.SUCCESS.getCode()));
        response.setMsg(ExceptionStatus.SUCCESS.getMessage());
        return response;

    }

    /**
     * @param paymentRequest 请求参数
     * @return QfResponse     返回参数
     */
    private QfPayContent DealCmPayRequest(PaymentRequest paymentRequest) {
        QfPayContent respContent = new QfPayContent();
        //入库
        PayDeal payDeal = payBaseService.prePayment(paymentRequest);
        //填写返回参数
        respContent.setTitle(CmPayConfig.CM_PAY_TITLE);
        respContent.setAuthedAmount(payDeal.getRequestAmount().toString());
        respContent.setTrade_id(payDeal.getTradeId());
        respContent.setPayPaymentNo(payDeal.getPayPaymentNo());
        respContent.setChannelName(payDeal.getPayChannel());
        respContent.setPayStatus(1);
        //已经成功直接返回//已经支付成功
        if (PayStatus.PAY_SUCCESS.getValue() == payDeal.getPayStatus()) {
            respContent.setHaspayed("true");
            return respContent;
        }
        //调用第三方进行支付
        String qfPayResult = this.requestCmChannel(payDeal, paymentRequest);
        respContent.setHaspayed("false");

        respContent.setResult(JSON.parseObject((qfPayResult)));
        //记录操作日志
        payLogService.insertLog(payDeal.getPayId(), payDeal.getPayPaymentNo(), payDeal.getTradeId(), PayStatus.CREATE_PAYMENT.getValue(), BusinessConstant.OPERATE_SUCCESS, JSON.toJSONString(paymentRequest), JSON.toJSONString(respContent),paymentRequest.getVenderId());

        return respContent;
    }

    /**
     * 调用第三方进行支付
     *
     * @param payDeal        支付平台记录
     * @param paymentRequest 下单请求参数
     * @return 请求返回参数
     */
    private String requestCmChannel(PayDeal payDeal, PaymentRequest paymentRequest) {
        PayDeal payDealUpd = new PayDeal();
        payDealUpd.setPayId(payDeal.getPayId());
        //调用收钱吧支付
        Map<String, String> requestMap = new HashMap<>(5);
        requestMap.put("payPaymentNo", payDeal.getPayPaymentNo());
        requestMap.put("payAmount", payDeal.getRequestAmount().toString());
        requestMap.put("channelType", paymentRequest.getTrade_type());
        requestMap.put("venderId", payDeal.getVenderId() + "");
        CmPayResponse ipcPayResponse = (CmPayResponse) strategies.generatePayParams(BusinessConstant.CMPAY, requestMap);

        //根据第三方返回信息分别处理
        if (ipcPayResponse != null && BusinessConstant.PAY_REQUEST_SUCCESS.equals(ipcPayResponse.getCode())) {
            logger.info("调收钱吧下单成功:" + payDeal.getPayId());
            //更新流水中的订单号
            JSONObject dataJson = JSON.parseObject(ipcPayResponse.getMsg());
            payDealUpd.setChannelTransaction(dataJson.getString("sn"));
            payDealUpd.setPayStatus(PayStatus.PAYING.getValue());
            if (payDealService.updatePayDeal(payDealUpd) > 0) {
                //插入task
                PayEventBus.post(new payTaskModel(payDeal));
                //返回参数处理
                return ipcPayResponse.getMsg();
            } else {
                logger.error("收钱吧 下单后,更新支付流水失败:" + payDeal.getPayPaymentNo());
                throw new BusinessException(ExceptionStatus.E2003001.getCode(), ExceptionStatus.E2003001.getMessage());
            }
        } else {
            logger.error("调收钱吧下单失败:" + payDeal.getPayId());
            throw new BusinessException(ExceptionStatus.E2001005.getCode(), ExceptionStatus.E2001005.getMessage());
        }
    }
}
